package com.example.study.source

import android.os.Environment
import com.example.study.source.CustomOkHttpClient.ProgressResponseBody.Companion.cacheDir
import okhttp3.Cache
import okhttp3.MediaType
import okhttp3.OkHttpClient
import okhttp3.ResponseBody
import okio.Buffer
import okio.BufferedSource
import okio.ForwardingSource
import okio.Okio
import okio.Source
import java.io.File

/**
 * Created by lijinxi on 2024/3/1
 * @Description:
 */
class CustomOkHttpClient(private val listener: ProgressListener) {

    interface ProgressListener {
        fun onProgress(progress: Int)
    }

    fun client(): OkHttpClient {
        return OkHttpClient().newBuilder().cache(Cache(cacheDir, 10 * 1024 * 1024))
            .addNetworkInterceptor { chain ->
                val originalResponse = chain.proceed(chain.request())
                originalResponse.newBuilder()
                    .body(ProgressResponseBody(originalResponse.body()!!, listener))
                    .build()
            }.build()
    }

    class ProgressResponseBody(
        private val body: ResponseBody,
        private val listener: ProgressListener
    ) :
        ResponseBody() {
        private var bufferSource: BufferedSource? = null

        override fun contentType(): MediaType? {
            return body.contentType()
        }

        override fun contentLength(): Long {
            return body.contentLength() ?: 0
        }

        override fun source(): BufferedSource {
            if (bufferSource == null) {
                bufferSource = Okio.buffer(source(body.source())) as BufferedSource
            }
            return bufferSource as BufferedSource
        }

        private fun source(source: Source): Source {
            return object : ForwardingSource(source) {
                var totalBytesRead = 0L
                override fun read(sink: Buffer, byteCount: Long): Long {
                    val bytesRead = super.read(sink, byteCount)
                    totalBytesRead += if (bytesRead.toInt() != -1) {
                        bytesRead
                    } else {
                        0
                    }
                    listener.onProgress((100 * totalBytesRead / body.contentLength()).toInt())
                    return bytesRead
                }
            }
        }

        companion object {
            val cacheDir = File(Environment.getDownloadCacheDirectory().absolutePath)
        }
    }
}

